import 'package:flutter/foundation.dart';

class DDAction {
  final String name;
  final Function? callback;
  bool _disposed = false;
  DDAction({required this.name, required this.callback});
}

enum DDActionFutureType {
  none,
  wait,
  any,
}

class DDNotifier {
  @nonVirtual
  List<DDAction> _actions = [];
  @nonVirtual
  bool _disposed = false;
  @nonVirtual
  int _notificationCallStackDepth = 0;

  @mustCallSuper
  void addListener({required String name, required Function callback}) {
    assert(!_disposed, "DDNotifier:已经释放了，不能再添加新的监听");
    final index =
        _actions.indexWhere((element) => element.name == name && element.callback == callback);
    if (_notificationCallStackDepth == 0) {
      if (index != -1) {
        _actions[index] = DDAction(name: name, callback: callback);
      } else {
        _actions.add(DDAction(name: name, callback: callback));
      }
      return;
    }
    assert(index != -1, "DDNotifier:在嵌套回调里添加新的监听会有未知后果");
    if (index != -1) {
      _actions[index] = DDAction(name: name, callback: callback);
    }
  }

  @mustCallSuper
  void removeListener({required String name, required Function callback}) {
    assert(!_disposed, "DDNotifier:已经释放了，不能再移除监听");
    final index =
        _actions.indexWhere((element) => element.name == name && element.callback == callback);
    if (index == -1) {
      debugPrint("DDNotifier:当前移除的对象不存在：$name");
      return;
    }
    if (_notificationCallStackDepth > 0) {
      _actions[index]._disposed = true;
    } else {
      _actions.removeWhere((element) =>
          (element.name == name && element.callback == callback) || element.callback == null);
    }
  }

  List<String> _tempNames = [];
  @mustCallSuper
  dynamic dispatch(
    String name, {
    DDActionFutureType type = DDActionFutureType.none,
    List<dynamic>? positionalArguments,
    Map<Symbol, dynamic>? namedArguments,
  }) {
    assert(!_disposed, "DDNotifier:已经释放了，不能再dispose操作");
    assert(_tempNames.indexOf(name) == -1, "DDNotifier:当前dispatch嵌套里已经存在相同事件了，重复派发会导致死循环");
    _tempNames.add(name);
    List<Future> futures = [];
    List results = [];
    dynamic assertWrong;
    _notificationCallStackDepth++;
    try {
      for (var element in _actions) {
        if (element.name == name && element.callback != null) {
          final future = Function.apply(element.callback!, positionalArguments, namedArguments);
          results.add(future);
          if (type != DDActionFutureType.none) {
            if (future is Future) {
              futures.add(future);
            } else {
              futures.add(Future.value(future));
            }
          }
        }
      }
    } catch (e) {
      assertWrong = e.toString();
    }
    assert(assertWrong == null, "DDNotifier:循环遍历失败：$name, 原因：$assertWrong");
    if (results.isEmpty) {
      debugPrint("DDNotifier：当前：$name,没有监听者");
    }
    _notificationCallStackDepth--;
    if (_notificationCallStackDepth == 0) {
      _tempNames = [];
      if (_disposed) {
        _actions = [];
      }
      _actions.removeWhere((element) => (element._disposed) || element.callback == null);
    }
    if (type == DDActionFutureType.wait) {
      return Future.wait(futures);
    } else if (type == DDActionFutureType.any) {
      return Future.any(futures);
    } else {
      return results;
    }
  }

  @mustCallSuper
  void dispose() {
    if (_notificationCallStackDepth == 0) {
      _disposed = true;
      _actions = [];
    } else {
      _disposed = true;
    }
  }
}
